﻿//-----------------------------------------------------------------------
// <copyright file="Locator.cs" company="Microsoft">
//     Copyright (c) AGALTIER, Microsoft. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace ArchiSimple.Windows
{
    using System;
    using System.Linq;
    using System.Windows;
    using ArchiSimple.Windows.ViewModel;
    using GalaSoft.MvvmLight.Command;
    using Ninject;
    using Ninject.Extensions.Conventions;
    using Ninject.Extensions.Interception;
    using Ninject.Extensions.Interception.Infrastructure.Language;
    using ArchiSimple.Windows.Tools;
    using System.Collections.Generic;
    using Ninject.Parameters;

    /// <summary>
    /// TODO: Provide summary section in the documentation header.
    /// </summary>
    public class Locator
    {
        private static IKernel kernel;

        static Locator()
        {
            if (!ViewModelBase.IsInDesignModeStatic)
            {
                InitKernel();
            }
        }

        /// <summary>
        /// TODO : Make this private.
        /// </summary>
        public static void InitKernel()
        {
            Locator.kernel = new StandardKernel();

            kernel.Bind(a => a.FromAssembliesMatching().SelectAllClasses().InheritedFrom<ViewModelBase>().BindToSelf());
            kernel.Bind<Designer>().ToSelf();
        }

        public static Type GetLocate(DependencyObject obj)
        {
            return (Type)obj.GetValue(LocateProperty);
        }

        public static void SetLocate(DependencyObject obj, Type value)
        {
            obj.SetValue(LocateProperty, value);
        }

        // Using a DependencyProperty as the backing store for Locate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LocateProperty =
            DependencyProperty.RegisterAttached("Locate", typeof(Type), typeof(Locator), new PropertyMetadata(LocateChange));

        public static void LocateChange(object sender, DependencyPropertyChangedEventArgs e)
        {
            var userControl = sender as FrameworkElement;

            if (userControl.DataContext == null)
            {
                var t = e.NewValue as Type;

                if (ViewModelBase.IsInDesignModeStatic)
                {
                    var constructor = t.GetConstructors().First();
                    var parameters = constructor.GetParameters();
                    var parametersObject = new List<object>();

                    foreach (var parameter in parameters)
                    {
                        if (parameter.ParameterType.IsClass)
                        {
                            parametersObject.Add(null);
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }

                    userControl.DataContext = constructor.Invoke(parameters.ToArray()) as ViewModelBase;
                }
                else
                {
                    var vm = Locator.kernel.Get(t) as ViewModelBase;
                    vm.Init();

                    userControl.DataContext = vm;
                }
            }
        }

        public static T Locate<T>(object o)
        {
            var parameters = new List<Ninject.Parameters.IParameter>();

            if (o != null)
            {
                foreach (var prop in o.GetType().GetProperties())
                {
                    parameters.Add(new ConstructorArgument(prop.Name, prop.GetValue(o, new object[0])));
                }
            }

            return kernel.Get<T>(parameters.ToArray());
        }
    }
}
